using System;
using System.Reflection;
using FireStarter.Base;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.UI.Relationship;
using Habanero.Faces.Base;
using Habanero.Util;
using NUnit.Framework;

namespace FireStarterModeller.Test.UI.Relationships
{
    [TestFixture]
    public class TestCreateRelationshipWizardStep2
    {
        [SetUp]
        public void SetupTest()
        {
            //Runs every time that any testmethod is executed
            UITestUtils.SetupTest();
        }

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            //Code that is executed before any test is run in this class. If multiple tests
            // are executed then it will still only be called once.
            UITestUtils.SetupFixture();
        }

        [TearDown]
        public void TearDownTest()
        {
            //runs every time any testmethod is complete
        }

        [Test]
        public void Test_CreateStep_WithNullRelationship_ThrowsError()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new CreateRelationshipWizardStep2( null, GlobalUIRegistry.ControlFactory);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("relationship", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateStep_WithNullControlFactory_ThrowsError()
        {
            //---------------Set up test pack-------------------
            DMClass ownerClass = TestUtilsDMClass.CreateSavedDMClass();
            DMRelationshipCreator relationshipCreator = new DMRelationshipCreator(ownerClass);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new CreateRelationshipWizardStep2(relationshipCreator, null);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("controlFactory", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateStep_WithRelationship_SetRelationship()
        {
            //---------------Set up test pack-------------------
            DMClass ownerClass = TestUtilsDMClass.CreateSavedDMClass();
            DMRelationshipCreator relationshipCreator = new DMRelationshipCreator(ownerClass);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------


            CreateRelationshipWizardStep2 step2 = new CreateRelationshipWizardStep2(relationshipCreator, GlobalUIRegistry.ControlFactory);
            //---------------Test Result -----------------------
            Assert.IsNotNull(step2);
            Assert.AreSame(relationshipCreator.Relationship, step2.Relationship);
            Assert.AreEqual("Step2: Select Create Foreign Key", step2.HeaderText);
        }

        [Test]
        public void Test_Construct_ShouldSetUpControlsOnStep()
        {
            DMClass ownerClass = TestUtilsDMClass.CreateSavedDMClass();
            DMRelationshipCreator relationshipCreator = new DMRelationshipCreator(ownerClass);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            CreateRelationshipWizardStep2 step2 = new CreateRelationshipWizardStep2(relationshipCreator, GlobalUIRegistry.ControlFactory);
            //---------------Test Result -----------------------
            Assert.AreEqual(5, step2.Controls.Count);
        }

        [Test]
        public void Test_InitialiseStep_ShouldDefaultControls()
        {
            //---------------Set up test pack-------------------]
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2) GetStep2();
            //---------------Execute Test ----------------------
            step2.InitialiseStep();
            //---------------Test Result -----------------------
            Assert.AreEqual(4, step2.CardinalityComboBox.Items.Count);
            Assert.IsNotNull(step2.CardinalityComboBox.SelectedItem);

            Assert.AreEqual("OneToMany",step2.CardinalityComboBox.SelectedItem.ToString());
            string message;
            Assert.IsTrue(step2.CanMoveOn(out message), "Defaults All Relationship Props to Sensible Values " + message);
        }

        [Test]
        public void Test_InitialiseStep_ShouldBeAbleToGetCreatedRelationship()
        {
            //---------------Set up test pack-------------------]
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2) GetStep2();
            //---------------Execute Test ----------------------
            step2.InitialiseStep();
            //---------------Test Result -----------------------
            Assert.AreSame(step2.Relationship, step2.CreatedRelationship);
        }

        [Test]
        public void Test_CanMoveBack_True()
        {
            //---------------Set up test pack-------------------
            IWizardStep step2 = GetStep2();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            bool canMoveBack = step2.CanMoveBack();
            //---------------Test Result -----------------------
            Assert.IsTrue(canMoveBack);
        }

        [Test]
        public void Test_Initialise_ShouldSetUpCreateForeignKeyTrue()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationShipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationShipCreator);
            //---------------Assert Precondition----------------
            Assert.IsFalse(step2.IsInitialised);
            //---------------Execute Test ----------------------
            step2.InitialiseStep();
            bool createFK = step2.MustCreateForeignKey;
            //---------------Test Result -----------------------
            Assert.IsTrue(createFK);
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
        }

        [Test]
        public void Test_CreateFKCheckBox_False_ShouldSetCreateForeignKeyFalse()
        {
            //---------------Set up test pack-------------------
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2();
            step2.InitialiseStep();
            //---------------Assert Precondition----------------
            Assert.IsTrue(step2.IsInitialised);
            //---------------Execute Test ----------------------
            step2.CreateFKCheckBox.Checked = false;
            bool createFK = step2.MustCreateForeignKey;
            //---------------Test Result -----------------------
            Assert.IsFalse(createFK);
            Assert.IsFalse(step2.CreateFKCheckBox.Checked);
        }

        [Test]
        public void Test_CreateFKCheckBox_False_ShouldNotDisableCardinalityComboBox()
        {
            //Changed behaviour for step 2
            //---------------Set up test pack-------------------
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2();
            step2.InitialiseStep();
            //---------------Assert Precondition----------------
            Assert.IsTrue(step2.IsInitialised);
            //---------------Execute Test ----------------------
            step2.CreateFKCheckBox.Checked = false;
            bool createFK = step2.MustCreateForeignKey;
            //---------------Test Result -----------------------
            Assert.IsFalse(createFK);
            Assert.IsFalse(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
        }

        [Test]
        public void Test_CreateFKCheckBoxEnabled_WhenCanCreateForeignKey_ShouldBeTrue()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationShipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2( out relationShipCreator);
            step2.InitialiseStep();
            //---------------Assert Precondition----------------
            Assert.IsTrue(step2.IsInitialised);
            Assert.IsTrue(relationShipCreator.CanCreateForeignKey);
            //---------------Execute Test ----------------------
            bool fkCheckBoxEnabled = step2.CreateFKCheckBox.Enabled;
            //---------------Test Result -----------------------
            Assert.IsTrue(fkCheckBoxEnabled);
            Assert.IsTrue(step2.MustCreateForeignKey);
        }

        [Test]
        public void Test_CreateFKCheckBoxEnabled_WhenCanCreateForeignKeyFalse_ShouldBeFalse()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationShipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2( out relationShipCreator);
            relationShipCreator.RelatedDMClass.ObjectIdentity.Properties.RemoveAll(property => true);
            step2.InitialiseStep();
            //---------------Assert Precondition----------------
            Assert.IsTrue(step2.IsInitialised);
            Assert.IsFalse(relationShipCreator.CanCreateForeignKey);
            //---------------Execute Test ----------------------
            bool fkCheckBoxEnabled = step2.CreateFKCheckBox.Enabled;
            //---------------Test Result -----------------------
            Assert.IsFalse(fkCheckBoxEnabled);
            Assert.IsFalse(step2.MustCreateForeignKey);
        }

        [Test]
        public void Test_InitialiseStep_ShouldCreateComboBox_WithCorrectOptions()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            step2.InitialiseStep();
            //---------------Test Result -----------------------
            Assert.IsNotNull(step2.CardinalityComboBox);
            Assert.IsInstanceOf(typeof (IComboBox), step2.CardinalityComboBox);
            Assert.AreEqual(4,step2.CardinalityComboBox.Items.Count,"This includes one blank item"); 
        }

        [Test]
        public void Test_CanMoveOn_WhenSelectedCreateFK_AndCardinalitySet_ShouldBeTrue()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = Cardinality.Multiple.ToString();
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.AreEqual("OneToMany", step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            string message;
            bool canMoveOn = step2.CanMoveOn(out message);
            //---------------Test Result -----------------------
            Assert.IsTrue(canMoveOn);
            Assert.AreEqual(string.Empty, message);
        }

        [Test]
        public void Test_CanMoveOn_WhenNotSelectedCreateFK_AndCardinalityNotSet_ShouldBeFalse()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = false;
            step2.CardinalityComboBox.SelectedItem = null;
            //--------------Assert Preconditions ---------------
            Assert.IsFalse(step2.MustCreateForeignKey);
            Assert.IsNull(step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            string message;
            bool canMoveOn = step2.CanMoveOn(out message);
            //---------------Test Result -----------------------
            Assert.IsFalse(canMoveOn);
            Assert.AreEqual("You cannot move on since no cardinality has been selected", message);
        }

/*        [Test]
        public void Test_MoveOnWhenNotSetFK_AndCardinalityNotSet_ShouldSetRelationshipCreator()
        {
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = false;
            step2.CardinalityComboBox.SelectedItem = null;
            //--------------Assert Preconditions ---------------
            Assert.IsFalse(step2.CreateFKCheckBox.Checked);
            Assert.IsNull(step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            step2.MoveOn();
            //---------------Test Result -----------------------
            Assert.IsFalse(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.ManyToOne, relationshipCreator.RelationshipCardinality);
        }*/
        [Test]
        public void Test_CanMoveOn_WhenSelectedCreateFK_AndCardinalityNotSet_ShouldBeFalse()
        {
            //---------------Set up test pack-------------------
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2();
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = null;
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.IsNull(step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            string message;
            bool canMoveOn = step2.CanMoveOn(out message);
            //---------------Test Result -----------------------
            Assert.IsFalse(canMoveOn);
            Assert.AreEqual("You cannot move on since no cardinality has been selected", message);
        }

        [Test]
        public void Test_MoveOn_ShouldSetSelectedCreateFK_AndCardinality()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = Cardinality.Multiple.ToString();
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.AreEqual("OneToMany", step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            step2.MoveOn();
            //---------------Test Result -----------------------
            Assert.IsTrue(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.OneToMany, relationshipCreator.RelationshipCardinality);
        }

        [Test]
        public void Test_MoveOn_ShouldSetSelectedCreateFK_AndCardinalitySetToManyToOne()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = "ManyToOne";
            relationshipCreator.RelationshipCardinality = RelationshipCardinality.OneToMany;
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.AreEqual("ManyToOne", step2.CardinalityComboBox.SelectedItem);
            Assert.AreNotEqual(RelationshipCardinality.ManyToOne, relationshipCreator.RelationshipCardinality);
            //---------------Execute Test ----------------------
            step2.MoveOn();
            //---------------Test Result -----------------------
            Assert.IsTrue(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.ManyToOne, relationshipCreator.RelationshipCardinality);
        }

        [Test]
        public void Test_MoveOn_WhenOneToOne_AndCardinalitySetToOneToOne()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            const string selectedCardinality = "OneToOne";
            step2.CardinalityComboBox.SelectedItem = selectedCardinality;
            relationshipCreator.RelationshipCardinality = RelationshipCardinality.OneToMany;
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.AreEqual(selectedCardinality, step2.CardinalityComboBox.SelectedItem);
            Assert.AreNotEqual(RelationshipCardinality.OneToOne, relationshipCreator.RelationshipCardinality);
            //---------------Execute Test ----------------------
            step2.MoveOn();
            //---------------Test Result -----------------------
            Assert.IsTrue(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.OneToOne, relationshipCreator.RelationshipCardinality);
        }

        [Test]
        public void Test_MoveOn_WhenSelectedCreateFK_AndCardinalitySetMultiple_ShouldBeSetupRelationship()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = Cardinality.Multiple.ToString();
            //--------------Assert Preconditions ---------------
            Assert.IsTrue(step2.CreateFKCheckBox.Checked);
            Assert.IsTrue(step2.CardinalityComboBox.Enabled);
            Assert.AreEqual("OneToMany", step2.CardinalityComboBox.SelectedItem);
            //---------------Execute Test ----------------------
            step2.MoveOn();
            //---------------Test Result -----------------------
            Assert.IsTrue(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.OneToMany, relationshipCreator.RelationshipCardinality);
            DMRelationship relationship = relationshipCreator.Relationship;
            Assert.IsNotNull(relationship.RelatedClass);
            Assert.AreEqual(StringUtilities.Pluralize(relationship.RelatedClass.ClassNameBO), relationship.RelationshipName);
            Assert.AreEqual(1, relationship.RelationshipProperties.Count);
        }
        [Test]
        public void Test_UndoMoveOn_WhenCreatedProps_ShouldCancelEditsOnRelationship()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            step2.InitialiseStep();
            step2.CreateFKCheckBox.Checked = true;
            step2.CardinalityComboBox.SelectedItem = Cardinality.Multiple.ToString();
            string message;
            DMRelationship relationship = relationshipCreator.Relationship;
            var relatedClass = relationship.RelatedClass;
            Assert.AreEqual(1, relatedClass.Properties.Count);
            bool canMoveOn = step2.CanMoveOn(out message);
            step2.MoveOn();
            //---------------Assert Precondition----------------
            Assert.IsTrue(canMoveOn, message);
            Assert.AreEqual(string.Empty, message);
            Assert.IsTrue(relationshipCreator.MustCreateForeignKeyProp);
            Assert.AreEqual(RelationshipCardinality.OneToMany, relationshipCreator.RelationshipCardinality);
            
            
            Assert.IsNotNull(relatedClass);
            Assert.AreEqual(StringUtilities.Pluralize(relatedClass.ClassNameBO), relationship.RelationshipName);
            Assert.AreEqual(1, relationship.RelationshipProperties.Count);

            Assert.AreEqual(2, relatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            step2.UndoMoveOn();
            //---------------Test Result -----------------------
            Assert.IsNotNull(relationship.ReverseRelationship);
            Assert.IsNotNull(relationship.RelatedClass);
            Assert.IsNull(relationship.RelationshipName);
            Assert.AreEqual(0, relationship.RelationshipProperties.Count);
            Assert.AreEqual(1, relatedClass.Properties.Count);
        }

        [Test]
        public void Test_CanMoveBack_ShouldReturnTrue()
        {
            //---------------Set up test pack-------------------
            DMRelationshipCreator relationshipCreator;
            CreateRelationshipWizardStep2 step2 = (CreateRelationshipWizardStep2)GetStep2(out relationshipCreator);
            bool canMoveBack = step2.CanMoveBack();
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            step2.CanMoveBack();
            //---------------Test Result -----------------------
            Assert.IsTrue(canMoveBack);
        }

        [Test]
        public void Test_InitialiseStep_WhenSelfReferencingRelationship_ShouldDisplayCorrectInformationLabel_()
        {
            //---------------Set up test pack-------------------
            //Relate a class to itself- A Part that has a relationship to other Parts
            //Should allow user to map properties as default of PK to PK is meaningless in this situation
            DMObjectIdentity dmObjectIdentity = TestUtilsShared.CreateUnsavedValidObjectIdentityInfo();
            DMClass dmClass = dmObjectIdentity.Class;
            DMRelationshipCreator relationshipCreator = new DMRelationshipCreator(dmClass)
                            {
                                RelatedDMClass = dmClass
                            };

            CreateRelationshipWizardStep2 step2 = new CreateRelationshipWizardStep2(relationshipCreator, GlobalUIRegistry.ControlFactory);
            //---------------Assert Precondition----------------
            Assert.IsNotNull(dmClass.ObjectIdentity);
            //---------------Execute Test ----------------------

            //---------------Execute Test ----------------------
            step2.InitialiseStep();
            //---------------Test Result -----------------------
            object label = ReflectionUtilities.GetPrivatePropertyValue(step2, "MessageLabel");
            Assert.AreSame("", ((ILabel)label).Text);
        }

        private static IWizardStep GetStep2(out DMRelationshipCreator relationshipCreator)
        {
            DMClass ownerClass = TestUtilsDMClass.CreateUnsavedValidDMClass();
            TestUtilsShared.CreateSavedObjectIdentityInfo(ownerClass);
            var relatedClass = TestUtilsDMClass.CreateUnsavedValidDMClass();
            TestUtilsShared.CreateSavedObjectIdentityInfo(relatedClass);
            relationshipCreator = new DMRelationshipCreator(ownerClass) {RelatedDMClass = relatedClass};
            return new CreateRelationshipWizardStep2(relationshipCreator, GlobalUIRegistry.ControlFactory);
        }

        private static IWizardStep GetStep2()
        {
            DMClass ownerClass = TestUtilsDMClass.CreateUnsavedValidDMClass();
            DMRelationshipCreator relationshipCreator = new DMRelationshipCreator(ownerClass)
                            {
                                RelatedDMClass =
                                    TestUtilsDMClass.CreateUnsavedValidDMClass()
                            };
            return new CreateRelationshipWizardStep2(relationshipCreator, GlobalUIRegistry.ControlFactory);
        }
    }
}